#ifndef NANE_IO_H
#   define NANE_IO_H

#   include "IInput.h"
#   include "IOutput.h"
#   include "IFileSystem.h"


namespace nane
{
    
    struct IOUnsafe
    {
        template<typename T>
        static uint32 Read( IInput* _input, T* _value )
        {
            return _input->Read(reinterpret_cast<byte*>(_value), sizeof(T));
        }
        
        template<size_t N, typename T>
        static uint32 read( IInput* _input, T (*_value)[N] )
        {
            return _input->Read(reinterpret_cast<byte*>(_value), sizeof(T) * N);
        }
        
        template<typename T>
        static uint32 Write( IOutput* _output, const T& _value )
        {
            return _output->Write(reinterpret_cast<const byte*>(&_value), sizeof(T));
        }
        
        template<size_t N, typename T>
        static uint32 Write( IOutput* _output, const T _value[N] )
        {
            return _output->Write(reinterpret_cast<const byte*>(_value), sizeof(T) * N);
        }
        
        static uint32 Skip( ISeekable* _file, uint32 _count );
    };
    
    template<>
    uint32 IOUnsafe::Write<const char*>( IOutput* _output, const char* const& _value );

    struct IOSafe
    {
        template<typename T>
        static uint32 Read( IInput* _input, T* _value )
        {
            if( _input != NULL && _value != NULL )
            {
                return IOUnsafe::Read(_input, _value);
            }
            return 0;
        }
        
        template<size_t N, typename T>
        static uint32 Read( IInput* _input, T (*_value)[N] )
        {
            if( _input != NULL && _value != NULL )
            {
                return IOUnsafe::template Read<N, T>(_input, _value);
            }
            return 0;
        }
        
        template<typename T>
        static uint32 Write( IOutput* _output, const T& _value )
        {
            if( _output != NULL )
            {
                return IOUnsafe::Write(_output, _value);
            }
            return 0;
        }
        
        template<size_t N, typename T>
        static uint32 Write( IOutput* _output, const T _value[N] )
        {
            if( _output != NULL && _value != NULL )
            {
                return IOUnsafe::Write(_output, _value);
            }
            return 0;
        }
        
        static uint32 Skip( ISeekable* _file, uint32 _count )
        {
            if( _file != NULL )
            {
                return IOUnsafe::Skip(_file, _count);
            }
            return 0;
        }
        
    };
    
    template<class SafetyPolicy>
    struct IO
    {
        template<typename T>
        static uint32 Read( IInput* _input, T* _value )
        {
            return SafetyPolicy::Read(_input, _value);
        }
        
        template<size_t N, typename T>
        static uint32 read( IInput* _input, T _value[N] )
        {
            return SafetyPolicy::template Read<N, T>(_input, _value);
        }
        
        template<typename T>
        static uint32 Write( IOutput* _output, const T& _value )
        {
            return SafetyPolicy::Write(_output, _value);
        };
        
        template<size_t N, typename T>
        static uint32 Write( IOutput* _output, const T _value[N] )
        {
            return SafetyPolicy::Write(_output, _value);
        }
        
        static uint32 Writeln( IOutput* _output, const char* _value )
        {
            uint32 o = SafetyPolicy::Write(_output, _value);
            return o + SafetyPolicy::Write(_output, '\n');
        }
        
        static uint32 Skip( ISeekable* _file, uint32 _count )
        {
            return SafetyPolicy::Skip(_file, _count);
        }
    };
    
}   // namespace nane

#endif  // NANE_IO_H
